{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The Grid layout\n",
    "\n",
    "The `GridBox` class is a special case of the `Box` widget.\n",
    "\n",
    "The `Box` widget enables the entire CSS flexbox spec, enabling rich reactive layouts in the Jupyter notebook. It aims at providing an efficient way to lay out, align and distribute space among items in a container.\n",
    "\n",
    "Again, the whole grid layout spec is exposed via the `layout` attribute of the container widget (`Box`) and the contained items. One may share the same `layout` attribute among all the contained items.\n",
    "\n",
    "The following flexbox tutorial on the flexbox layout follows the lines of the article [A Complete Guide to Grid](https://css-tricks.com/snippets/css/complete-guide-grid/) by Chris House, and uses text and various images from the article [with permission](https://css-tricks.com/license/).\n",
    "\n",
    "### Basics and browser support\n",
    "\n",
    "To get started you have to define a container element as a grid with display: grid, set the column and row sizes with grid-template-rows, grid-template-columns, and grid_template_areas, and then place its child elements into the grid with grid-column and grid-row. Similarly to flexbox, the source order of the grid items doesn't matter. Your CSS can place them in any order, which makes it super easy to rearrange your grid with media queries. Imagine defining the layout of your entire page, and then completely rearranging it to accommodate a different screen width all with only a couple lines of CSS. Grid is one of the most powerful CSS modules ever introduced.\n",
    "\n",
    "As of March 2017, most browsers shipped native, unprefixed support for CSS Grid: Chrome (including on Android), Firefox, Safari (including on iOS), and Opera. Internet Explorer 10 and 11 on the other hand support it, but it's an old implementation with an outdated syntax. The time to build with grid is now!\n",
    "\n",
    "### Important terminology\n",
    "\n",
    "Before diving into the concepts of Grid it's important to understand the terminology. Since the terms involved here are all kinda conceptually similar, it's easy to confuse them with one another if you don't first memorize their meanings defined by the Grid specification. But don't worry, there aren't many of them.\n",
    "\n",
    "**Grid Container**\n",
    "\n",
    "The element on which `display: grid` is applied. It's the direct parent of all the grid items. In this example container is the grid container.\n",
    "\n",
    "```html\n",
    "<div class=\"container\">\n",
    "  <div class=\"item item-1\"></div>\n",
    "  <div class=\"item item-2\"></div>\n",
    "  <div class=\"item item-3\"></div>\n",
    "</div>\n",
    "```\n",
    "\n",
    "**Grid Item**\n",
    "\n",
    "The children (e.g. direct descendants) of the grid container. Here the item elements are grid items, but sub-item isn't.\n",
    "\n",
    "```html\n",
    "<div class=\"container\">\n",
    "  <div class=\"item\"></div> \n",
    "  <div class=\"item\">\n",
    "  \t<p class=\"sub-item\"></p>\n",
    "  </div>\n",
    "  <div class=\"item\"></div>\n",
    "</div>\n",
    "```\n",
    "\n",
    "**Grid Line**\n",
    "\n",
    "The dividing lines that make up the structure of the grid. They can be either vertical (\"column grid lines\") or horizontal (\"row grid lines\") and reside on either side of a row or column. Here the yellow line is an example of a column grid line.\n",
    "\n",
    "![grid-line](images/grid-line.png)\n",
    "\n",
    "**Grid Track**\n",
    "\n",
    "The space between two adjacent grid lines. You can think of them like the columns or rows of the grid. Here's the grid track between the second and third row grid lines.\n",
    "\n",
    "![grid-track](images/grid-track.png)\n",
    "\n",
    "**Grid Cell**\n",
    "\n",
    "The space between two adjacent row and two adjacent column grid lines. It's a single \"unit\" of the grid. Here's the grid cell between row grid lines 1 and 2, and column grid lines 2 and 3.\n",
    "\n",
    "![grid-cell](images/grid-cell.png)\n",
    "\n",
    "**Grid Area**\n",
    "\n",
    "The total space surrounded by four grid lines. A grid area may be comprised of any number of grid cells. Here's the grid area between row grid lines 1 and 3, and column grid lines 1 and 3.\n",
    "\n",
    "![grid-area](images/grid-area.png)\n",
    "\n",
    "### Properties of the parent\n",
    "\n",
    "**grid-template-rows, grid-template-colums**\n",
    "\n",
    "Defines the columns and rows of the grid with a space-separated list of values. The values represent the track size, and the space between them represents the grid line.\n",
    "\n",
    "Values:\n",
    "\n",
    "- `<track-size>` - can be a length, a percentage, or a fraction of the free space in the grid (using the `fr` unit)\n",
    "- `<line-name>` - an arbitrary name of your choosing\n",
    "\n",
    "**grid-template-areas** \n",
    "\n",
    "Defines a grid template by referencing the names of the grid areas which are specified with the grid-area property. Repeating the name of a grid area causes the content to span those cells. A period signifies an empty cell. The syntax itself provides a visualization of the structure of the grid.\n",
    "\n",
    "Values:\n",
    "\n",
    "- `<grid-area-name>` - the name of a grid area specified with `grid-area`\n",
    "- `.` - a period signifies an empty grid cell\n",
    "- `none` - no grid areas are defined\n",
    "\n",
    "**grid-gap** \n",
    "\n",
    "A shorthand for `grid-row-gap` and `grid-column-gap`\n",
    "\n",
    "Values:\n",
    "\n",
    "- `<grid-row-gap>`, `<grid-column-gap>` - length values\n",
    "\n",
    "where `grid-row-gap` and `grid-column-gap` specify the sizes of the grid lines. You can think of it like setting the width of the gutters between the columns / rows.\n",
    "\n",
    "- `<line-size>` - a length value\n",
    "\n",
    "*Note: The `grid-` prefix will be removed and `grid-gap` renamed to `gap`. The unprefixed property is already supported in Chrome 68+, Safari 11.2 Release 50+ and Opera 54+.*\n",
    "\n",
    "**align-items**\n",
    "\n",
    "Aligns grid items along the block (column) axis (as opposed to justify-items which aligns along the inline (row) axis). This value applies to all grid items inside the container.\n",
    "\n",
    "Values:\n",
    "\n",
    "- `start` - aligns items to be flush with the start edge of their cell\n",
    "- `end` - aligns items to be flush with the end edge of their cell\n",
    "- `center` - aligns items in the center of their cell\n",
    "- `stretch` - fills the whole height of the cell (this is the default)\n",
    "\n",
    "**justify-items**\n",
    "\n",
    "Aligns grid items along the inline (row) axis (as opposed to `align-items` which aligns along the block (column) axis). This value applies to all grid items inside the container.\n",
    "\n",
    "Values:\n",
    "\n",
    "- `start` - aligns items to be flush with the start edge of their cell\n",
    "- `end` - aligns items to be flush with the end edge of their cell\n",
    "- `center` - aligns items in the center of their cell\n",
    "- `stretch` - fills the whole width of the cell (this is the default)\n",
    "\n",
    "**align-content**\n",
    "\n",
    "Sometimes the total size of your grid might be less than the size of its grid container. This could happen if all of your grid items are sized with non-flexible units like `px`. In this case you can set the alignment of the grid within the grid container. This property aligns the grid along the block (column) axis (as opposed to justify-content which aligns the grid along the inline (row) axis).\n",
    "\n",
    "Values:\n",
    "\n",
    "- `start` - aligns the grid to be flush with the start edge of the grid container\n",
    "- `end` - aligns the grid to be flush with the end edge of the grid container\n",
    "- `center` - aligns the grid in the center of the grid container\n",
    "- `stretch` - resizes the grid items to allow the grid to fill the full height of the grid container\n",
    "- `space-around` - places an even amount of space between each grid item, with half-sized spaces on the far ends\n",
    "- `space-between` - places an even amount of space between each grid item, with no space at the far ends\n",
    "- `space-evenly` - places an even amount of space between each grid item, including the far ends\n",
    "\n",
    "**justify-content**\n",
    "\n",
    "Sometimes the total size of your grid might be less than the size of its grid container. This could happen if all of your grid items are sized with non-flexible units like `px`. In this case you can set the alignment of the grid within the grid container. This property aligns the grid along the inline (row) axis (as opposed to align-content which aligns the grid along the block (column) axis).\n",
    "\n",
    "Values:\n",
    "\n",
    "- `start` - aligns the grid to be flush with the start edge of the grid container\n",
    "- `end` - aligns the grid to be flush with the end edge of the grid container\n",
    "- `center` - aligns the grid in the center of the grid container\n",
    "- `stretch` - resizes the grid items to allow the grid to fill the full width of the grid container\n",
    "- `space-around` - places an even amount of space between each grid item, with half-sized spaces on the far ends\n",
    "- `space-between` - places an even amount of space between each grid item, with no space at the far ends\n",
    "- `space-evenly` - places an even amount of space between each grid item, including the far ends\n",
    "\n",
    "**grid-auto-columns, grid-auto-rows**\n",
    "\n",
    "Specifies the size of any auto-generated grid tracks (aka implicit grid tracks). Implicit tracks get created when there are more grid items than cells in the grid or when a grid item is placed outside of the explicit grid. (see The Difference Between Explicit and Implicit Grids)\n",
    "\n",
    "Values:\n",
    "\n",
    "- `<track-size>` - can be a length, a percentage, or a fraction of the free space in the grid (using the `fr` unit)\n",
    "\n",
    "### Properties of the items\n",
    "\n",
    "*Note: `float`, `display: inline-block`, `display: table-cell`, `vertical-align` and `column-??` properties have no effect on a grid item.*\n",
    "\n",
    "**grid-column, grid-row**\n",
    "\n",
    "Determines a grid item's location within the grid by referring to specific grid lines. `grid-column-start`/`grid-row-start` is the line where the item begins, and `grid-column-end`/`grid-row-end` is the line where the item ends.\n",
    "\n",
    "Values:\n",
    "\n",
    "- `<line>` - can be a number to refer to a numbered grid line, or a name to refer to a named grid line\n",
    "- `span <number>` - the item will span across the provided number of grid tracks\n",
    "- `span <name>` - the item will span across until it hits the next line with the provided name\n",
    "- `auto` - indicates auto-placement, an automatic span, or a default span of one\n",
    "\n",
    "```css\n",
    ".item {\n",
    "  grid-column: <number> | <name> | span <number> | span <name> | auto / \n",
    "               <number> | <name> | span <number> | span <name> | auto\n",
    "  grid-row: <number> | <name> | span <number> | span <name> | auto /\n",
    "            <number> | <name> | span <number> | span <name> | auto\n",
    "}\n",
    "```\n",
    "\n",
    "Examples:\n",
    "\n",
    "```css\n",
    ".item-a {\n",
    "  grid-column: 2 / five;\n",
    "  grid-row: row1-start / 3;\n",
    "}\n",
    "```\n",
    "\n",
    "![grid-start-end-a](images/grid-start-end-a.png)\n",
    "\n",
    "```css\n",
    ".item-b {\n",
    "  grid-column: 1 / span col4-start;\n",
    "  grid-row: 2 / span 2;\n",
    "}\n",
    "```\n",
    "\n",
    "![grid-start-end-b](images/grid-start-end-b.png)\n",
    "\n",
    "If no `grid-column` / `grid-row` is declared, the item will span 1 track by default.\n",
    "\n",
    "Items can overlap each other. You can use `z-index` to control their stacking order.\n",
    "\n",
    "**grid-area**\n",
    "\n",
    "Gives an item a name so that it can be referenced by a template created with the `grid-template-areas` property. Alternatively, this property can be used as an even shorter shorthand for `grid-row-start` + `grid-column-start` + `grid-row-end` + `grid-column-end`.\n",
    "\n",
    "Values:\n",
    "\n",
    "- `<name>` - a name of your choosing\n",
    "- `<row-start> / <column-start> / <row-end> / <column-end>` - can be numbers or named lines\n",
    "\n",
    "```css\n",
    ".item {\n",
    "  grid-area: <name> | <row-start> / <column-start> / <row-end> / <column-end>;\n",
    "}\n",
    "```\n",
    "\n",
    "Examples:\n",
    "\n",
    "As a way to assign a name to the item:\n",
    "\n",
    "```css\n",
    ".item-d {\n",
    "  grid-area: header\n",
    "}\n",
    "```\n",
    "\n",
    "As the short-shorthand for `grid-row-start` + `grid-column-start` + `grid-row-end` + `grid-column-end`:\n",
    "\n",
    "```css\n",
    ".item-d {\n",
    "  grid-area: 1 / col4-start / last-line / 6\n",
    "}\n",
    "```\n",
    "\n",
    "![grid-start-end-d](images/grid-start-end-d.png)\n",
    "\n",
    "**justify-self**\n",
    "\n",
    "Aligns a grid item inside a cell along the inline (row) axis (as opposed to `align-self` which aligns along the block (column) axis). This value applies to a grid item inside a single cell.\n",
    "\n",
    "Values:\n",
    "\n",
    "- `start` - aligns the grid item to be flush with the start edge of the cell\n",
    "- `end` - aligns the grid item to be flush with the end edge of the cell\n",
    "- `center` - aligns the grid item in the center of the cell\n",
    "- `stretch` - fills the whole width of the cell (this is the default)\n",
    "\n",
    "```css\n",
    ".item {\n",
    "  justify-self: start | end | center | stretch;\n",
    "}\n",
    "```\n",
    "\n",
    "Examples:\n",
    "\n",
    "```css\n",
    ".item-a {\n",
    "  justify-self: start;\n",
    "}\n",
    "```\n",
    "\n",
    "![Example of `justify-self` set to start](images/grid-justify-self-start.png)\n",
    "\n",
    "```css\n",
    ".item-a {\n",
    "  justify-self: end;\n",
    "}\n",
    "```\n",
    "\n",
    "![Example of `justify-self` set to end](images/grid-justify-self-end.png)\n",
    "\n",
    "```css\n",
    ".item-a {\n",
    "  justify-self: center;\n",
    "}\n",
    "```\n",
    "\n",
    "![Example of `justify-self` set to center](images/grid-justify-self-center.png)\n",
    "\n",
    "```css\n",
    ".item-a {\n",
    "  justify-self: stretch;\n",
    "}\n",
    "```\n",
    "\n",
    "![Example of `justify-self` set to stretch](images/grid-justify-self-stretch.png)\n",
    "\n",
    "To set alignment for *all* the items in a grid, this behavior can also be set on the grid container via the `justify-items` property."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from ipywidgets import Button, GridBox, Layout, ButtonStyle"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Placing items by name:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "header  = Button(description='Header',\n",
    "                 layout=Layout(width='auto', grid_area='header'),\n",
    "                 style=ButtonStyle(button_color='lightblue'))\n",
    "main    = Button(description='Main',\n",
    "                 layout=Layout(width='auto', grid_area='main'),\n",
    "                 style=ButtonStyle(button_color='moccasin'))\n",
    "sidebar = Button(description='Sidebar',\n",
    "                 layout=Layout(width='auto', grid_area='sidebar'),\n",
    "                 style=ButtonStyle(button_color='salmon'))\n",
    "footer  = Button(description='Footer',\n",
    "                 layout=Layout(width='auto', grid_area='footer'),\n",
    "                 style=ButtonStyle(button_color='olive'))\n",
    "\n",
    "GridBox(children=[header, main, sidebar, footer],\n",
    "        layout=Layout(\n",
    "            width='50%',\n",
    "            grid_template_rows='auto auto auto',\n",
    "            grid_template_columns='25% 25% 25% 25%',\n",
    "            grid_template_areas='''\n",
    "            \"header header header header\"\n",
    "            \"main main . sidebar \"\n",
    "            \"footer footer footer footer\"\n",
    "            ''')\n",
    "       )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Setting up row and column template and gap"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "GridBox(children=[Button(layout=Layout(width='auto', height='auto'),\n",
    "                         style=ButtonStyle(button_color='darkseagreen')) for i in range(9)\n",
    "                 ],\n",
    "        layout=Layout(\n",
    "            width='50%',\n",
    "            grid_template_columns='100px 50px 100px',\n",
    "            grid_template_rows='80px auto 80px', \n",
    "            grid_gap='5px 10px')\n",
    "       )"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "widgets-tutorial",
   "language": "python",
   "name": "widgets-tutorial"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
